package com.zhanghp.class039;

import java.util.TreeMap;

/**
 * 含有嵌套的分子式求原子数量<br/>
 * 测试链接 : https://leetcode.cn/problems/number-of-atoms/
 *
 * @author zhanghp
 * @since 2024/6/29 18:06
 */
public class Code03_NumberOfAtoms {


    public static int where;

     // treemap，字典序排序比较器
    // s[i....]开始计算，遇到字符串终止 或者 遇到 ) 停止
    // 返回 : 自己负责的这一段字符串的结果，有序表！
    // 返回之间，更新全局变量where，为了上游函数知道从哪继续！
    public static TreeMap<String, Integer> f(char[] c, int cur) {
        // ans是总表
        TreeMap<String, Integer> ans = new TreeMap<>();
        // 历史翻几倍
        int repeatNum = 0;
        // 之前收集到的有序表，历史一部分
        TreeMap<String, Integer> pre = null;
        //  之前收集到的名字，历史一部分（原子名称，大写字母+小写字母 或 大写字母）
        StringBuilder name = new StringBuilder();
        while (cur < c.length && c[cur] != ')') {
            if ((c[cur] >= 'A' && c[cur] <= 'Z') || c[cur] == '(') {
                // 进行一次之前数据处理 & 重置参数
                fill(ans, pre, name, repeatNum);
                name.setLength(0);
                repeatNum = 0;
                pre = null;

                // 进行本次索引处理
                if (c[cur] >= 'A' && c[cur] <='Z') {
                    name.append(c[cur ++]);
                }else {
                    // 说明碰到的是'('，递归处理，并重置索引
                    pre = f(c, cur + 1);
                    cur = where + 1;
                }
            } else if (c[cur] >= 'a' && c[cur] <= 'z') {
                name.append(c[cur++]);
            } else {
                repeatNum = repeatNum * 10 + c[cur++] - '0';
            }
        }
        fill(ans, pre, name, repeatNum);
        where = cur;
        return ans;

    }

    public static void fill(TreeMap<String, Integer> ans, TreeMap<String, Integer> pre, StringBuilder name, int repeat){
        // 两个都是空，直接不处理(只有第一次进来)
        // 2个属性是互斥的，所以一个有，另一个就没有
        if (name.length() >0 || pre!= null) {
            // 重复数字，若数字为0，说明是1
            repeat = (repeat == 0) ? 1 : repeat;
            // 原子名称处理，说明之前的嵌套集合为空
            if (name.length() > 0) {
                String key = name.toString();
                // 获取ans里的该原子数量，处理
                ans.put(key, ans.getOrDefault(key, 0)  +  repeat);
            }else {
                // 之前的嵌套集合结果处理 到 结果集
                for (String key : pre.keySet()) {
                    // pre嵌套集合 * repeat，并且 加 ans里的数量，重新塞入
                    ans.put(key, ans.getOrDefault(key, 0) + pre.get(key) * repeat);
                }
            }
        }

    }

    public String countOfAtoms(String formula) {
        StringBuilder sb = new StringBuilder();
        where = 0;
        TreeMap<String, Integer> treeMap = f(formula.toCharArray(), 0);
        treeMap.forEach((k, v) -> {
            sb.append(k);
            if (v > 1) {
                sb.append(v);
            }
        });
        return sb.toString();
    }
}
